/**
 * @file logger.cpp
 * @brief Logger class implementation
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; version 3 of the License.
 *
 * @author VestniK (Sergey N.Vidyuk) sir.vestnik@gmail.com
 * @date 16 Jan 2010
 */
#include "logger.h"

#include <QtCore/QMutexLocker>
#include <QtCore/QTextStream>

using namespace mjn;

QMutex Logger::mMutex;
QSharedPointer<Logger> Logger::mInstance;

LogMessageData::LogMessageData():
    time(QDateTime::currentDateTime()) {}

LogMessageData::LogMessageData(const QString& msg):
    time(QDateTime::currentDateTime()),
    message(msg) {}

LogMessageData::LogMessageData(const LogMessageData &other):
    QSharedData(other),
    time(other.time),
    message(other.message),
    severity(other.severity),
    type(other.type) {};


Logger::Logger(QObject *parent): QObject(parent) {
    qRegisterMetaType<LogMessage>("LogMessage");
    mDevice = 0;
}

Logger *Logger::instance() {
    QMutexLocker locker(&mMutex);
    if ( mInstance.isNull() ) {
        mInstance = QSharedPointer<Logger>( new Logger() );
    }
    return mInstance.data();
}

void Logger::log(Severity severity, Type type, const QString &msg, QThread *thread) {
    QMutexLocker locker(&mMutex);
    QString message;
    QTextStream stream(&message, QIODevice::WriteOnly);
    stream << "[thread (" << thread << ") " << thread->objectName() << "]: ";
    stream << msg;
    stream.flush();
    LogMessage logMsg(message);
    logMsg.setSeverity(severity);
    logMsg.setType(type);
    writeMsg(logMsg);
    emit newMessage(logMsg);
}

void Logger::writeMsg(const LogMessage &msg) {
    if ( mDevice == 0 ) {
        return;
    }
    QTextStream out(mDevice);
    out.setCodec("UTF-8");
    out << msg.time().toString("[yyyy-MM-dd hh:mm:ss.zzz] ");
    switch ( msg.severity() ) {
        case Logger::Error : out << "Error"; break;
        case Logger::Info : out << "Info"; break;
        case Logger::Debug : out << "Debug"; break;
    }
    switch ( msg.type() ) {
        case Logger::Network : out << "(Network): "; break;
        case Logger::Protocol : out << "(Protocol): "; break;
        case Logger::Session : out << "(Session): "; break;
        case Logger::Game : out << "(Game): "; break;
        case Logger::Other : out << "(Other): "; break;
    }
    out << msg.message() << endl;
}

void Logger::error(Type type,const QString &msg) {
    log(Logger::Error, type, msg, QThread::currentThread());
}

void Logger::info(Type type,const QString &msg) {
    log(Logger::Info, type, msg, QThread::currentThread());
}

void Logger::debug(Type type,const QString &msg) {
    log(Logger::Debug, type, msg, QThread::currentThread());
}
